/*
 * Copyright 2008 Nathan C Jones
 * 
 * This file is part of Fivehundred.
 * 
 * Fivehundred is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 * 
 * Fivehundred is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * Fivehundred. If not, see <http://www.gnu.org/licenses/>. 
 */

package com.googlecode.fivehundred.ui;

import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import com.googlecode.fivehundred.model.Card;
import com.googlecode.fivehundred.model.CardCollection;
import com.googlecode.fivehundred.model.CardCollectionListener;
import com.googlecode.fivehundred.model.Hand;

/**
 * Graphical representation of a hand of cards.
 * 
 * @author Nathan C Jones
 */
public class GraphicalHand extends CompositeGraphicalComponent implements CardCollectionListener {

	/** The hand being visualised. */
	private final Hand hand;

	/** The cards in the hand should be drawn face up. */
	private final boolean visible;

	/** The width in pixels of each of the cards in the hand. */
	private int width;

	/**
	 * Create a new graphical hand. The graphical hand will listen for card
	 * container events from the given hand.
	 * 
	 * @param hand the hand to visualise.
	 * @param width the width in pixels of each of the cards in the hand.
	 * @param visible <code>true</code> if the cards in the hand should be
	 *        drawn face up.
	 */
	public GraphicalHand(Hand hand, int width, boolean visible) {
		this.hand = hand;
		this.width = width;
		this.visible = visible;
		initialiseCards();
		hand.addCardCollectionListener(this);
	}

	private void initialiseCards() {
		final int cardWidth = this.width;
		final int fanRadius = cardWidth * 2;
		double rotateFactor = -(hand.size() - 1) / 2.0;
		for (Card card : hand) {
			final double angle = rotateFactor * Math.PI / 50;
			final GraphicalCard gCard = new GraphicalCard(card, cardWidth);
			final Point p = calculateCardPosition(fanRadius, angle);
			gCard.setPosition(p.x, p.y);
			gCard.setAngle(angle);
			rotateFactor++;
			add(gCard);
			new GraphicalCardMouseListener(gCard);
		}
	}

	/**
	 * @param radius
	 * @param angle
	 * @return
	 * @see "card fan geometry.odg" TODO create working hyperlink to the odg
	 *      document
	 */
	private static Point calculateCardPosition(final int radius, final double angle) {
		final int x = (int) (radius * Math.sin(angle));
		final int y = (int) (radius - radius * Math.cos(angle));
		return new Point(x, y);
	}

	public Hand getHand() {
		return hand;
	}

	public void cardAdded(Card card, CardCollection collection) {
		GraphicalCard gCard = new GraphicalCard(card, this.width);
		add(gCard); // TODO add gCard at the correct index. Probably requires
		// changing cardAdded signature to include index param.
	}

	public void cardRemoved(Card card, CardCollection collection) {
		// TODO map cards to gcards so we know which gcard to remove?
	}

	/**
	 * Selects a card when it is hovered over.
	 */
	private final class GraphicalCardMouseListener extends MouseAdapter {

		private final GraphicalCard card;

		private GraphicalCardMouseListener(GraphicalCard c) {
			card = c;
			card.addMouseListener(this);
			card.addMouseMotionListener(this);
		}

		@Override
		public void mouseEntered(MouseEvent e) {
			card.setSelected(true);
		}

		@Override
		public void mouseExited(MouseEvent e) {
			card.setSelected(false);
		}
	};
}
